home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / hypertxt / msdos / hs25 / pdbits.lzh / SNIPPER.ASM < prev    next >
Assembly Source File  |  1989-02-26  |  27KB  |  1,004 lines

  1. page 60,132
  2.  
  3. ; SNIPPER is a resident utility which allows cutting out a portion
  4. ; of the screen.  The selected portion may be printed, written
  5. ; to disk or entered in the keyboard buffer.  Activate SNIPPER by
  6. ; pressing ALT-W, then position the cursor in the upper left corner of
  7. ; the window using the arrow keys.  Press CR to fix the first corner,
  8. ; then expand the window with arrow keys.  Finally, type "P" to print,
  9. ; "F" for disk file, "G" to retrieve or CR for a help menu.  Press ESC
  10. ; any time to exit SNIPPER.  When installing SNIPPER, use the optional
  11. ; parameters to expand it's internal buffer for displays (such as the
  12. ; EGA) containing more than the standard 25 rows and 80 columns.
  13.  
  14. ; SNIPPER [rows,columns]
  15.  
  16. ; ------------------------------------; 
  17. ; BIOS_SEG IS THE ROM-BIOS DATA AREA ; 
  18. ; ------------------------------------; 
  19.  
  20. BIOS_SEG    SEGMENT    AT 0040H
  21.  
  22.     ORG    004AH
  23. CRT_COLS    DB    ?        ; CURRENT NUMBER OF COLUMNS
  24.  
  25.     ORG    0050H
  26. CURSOR_POSN    DW    8 DUP(?)    ; CURRENT CURSOR LOCATION
  27.  
  28.     ORG    0062H
  29. ACTIVE_PAGE    DB    ?        ; ACTIVE PAGE FOR CGA AND EGA
  30.  
  31.     ORG    0084H
  32. ROWS        DB    ?        ; LAST ROW NUMBER FOR EGA
  33.  
  34. BIOS_SEG    ENDS
  35.  
  36. CSEG        SEGMENT
  37.  
  38.     ASSUME    CS:CSEG,DS:NOTHING
  39.  
  40.     ORG    0100H        ; BEGINNING FOR .COM PROGRAMS
  41.  
  42. START:
  43.     JMP    INITIALIZE    ; INITIALIZATION CODE IS AT END
  44.  
  45. ; --------------------------------; 
  46. ; DATA AREA USED BY THIS PROGRAM ; 
  47. ; --------------------------------; 
  48.  
  49. HOTKEY        EQU    11H        ; SCAN CODE FOR "W" KEY
  50.  
  51. SHIFT_MASK    EQU    00001000B    ; MASK FOR ALT KEY
  52.  
  53. COPYRIGHT    DB    "SNIPPER 1.0 (c) 1987 Ziff Communications Co."
  54.     DB    13,10,"Hotkey is ALT-W",13,10,"$",1AH
  55.  
  56. PROGRAMMER    DB    "Tom Kihlken"
  57.  
  58. INSTALLED_MSG    DB    "Already Installed",13,10,"$"
  59.  
  60. BAD_DOS_MSG    DB    "Requires DOS 2.0+",13,10,"$"
  61.  
  62. OLDINT09    DD    ?    ; OLD KEYBOARD BREAK INTERRUPT VECTOR
  63.  
  64. OLDINT13    DD    ?    ; OLD BIOS DISK IO INTERRUPT VECTOR
  65.  
  66. OLDINT16    DD    ?    ; OLD KEYBOARD INTERRUPT VECTOR
  67.  
  68. OLDINT21    DD    ?    ; OLD DOS FUNCTION INTERRUPT VECTOR
  69.  
  70. ERR_STAT    DB    ?    ; ERROR STATUS DURING FILE OUTPUT
  71.  
  72. FILE_PROMPT    DB    "Enter Filename: "
  73.  
  74. FILENAME    DB    "SCREEN.CUT"    ; THE DEFAULT FILENAME
  75.     DB    15 DUP (0)    ; LEAVE ROOM FOR DRIVE AND PATH
  76.  
  77. BUFF_NEXT    DW    BUFF_START    ; POINTER TO NEXT KEY IN BUFFER
  78.  
  79. BUFF_LAST    DW    BUFF_START    ; POINTER TO LAST KEY IN BUFFER
  80.  
  81. BUFF_START    EQU    OFFSET INITIALIZE
  82.  
  83. BUFF_SIZE    EQU    25*(80+2)    ; ROOM FOR 25 ROWS OF 80 COLUMNS
  84.  
  85. BUFF_END    DW    BUFF_START+BUFF_SIZE
  86.  
  87. TOP_LEFT    LABEL    WORD        ; FIRST CORNER OF WINDOW
  88.  
  89. LEFT_SIDE    DB    0        ; COLUMN NUMBER OF LEFT SIDE
  90.  
  91. TOP_ROW        DB    0        ; ROW NUMBER OF TOP SIDE
  92.  
  93. BOT_RIGHT    LABEL    WORD        ; SECOND CORNER OF WINDOW
  94.  
  95. RIGHT_SIDE    DB    ?        ; COLUMN NUMBER OR RIGHT SIDE
  96.  
  97. BOT_ROW        DB    ?        ; ROW NUMBER OF BOTTOM
  98.  
  99. SEND_CHAR    DW    ?        ; POINTER TO CHARACTER HANDLER
  100.  
  101. SEND_KEYS    DB    0        ; IF=1, USE KEYSTROKES FROM BUFFER
  102.  
  103. WRIT_FILE    DB    0        ; IF=1, NEED TO WRITE TO DISK
  104.  
  105. BUSY_FLAGS    DB    0        ; BIT MASKED AS FOLLOWS:
  106.                     ; 1 - DOS IS ACTIVE
  107.                     ; 2 - BIOS IO IS ACTIVE
  108.                     ; 4 - SNIPPER IS ACTIVE
  109.  
  110. DOS_STAT    DB    0        ; CURRENT DOS FUNCTION
  111.  
  112. HELP_MENU    DB    201,10 DUP(205),187
  113.     DB    186," F - File ",186
  114.     DB    186," P - Print",186
  115.     DB    186," S - Save ",186
  116.     DB    186," G - Get  ",186
  117.     DB    186,"Esc- Quit ",186
  118.     DB    200,10 DUP(205),188
  119.  
  120. ; ------------------------------------------------------------------; 
  121. ; SNIPPER BUILDS THE WINDOW AND ACCEPTS COMMANDS FROM THE KEYBOARD ; 
  122. ; ------------------------------------------------------------------; 
  123. SNIPPER        PROC    NEAR
  124.  
  125.     ASSUME    DS:CSEG, ES:BIOS_SEG
  126.  
  127.     XOR    BX,BX        ; BX IS INCREMENT FOR ROW/COLUMN
  128.  
  129. GET_KB_KEY1:
  130.     MOV    DX,TOP_LEFT    ; GET LOCATION OF FIRST CORNER
  131.     ADD    DH,BH        ; ADD IN THE ROW INCREMENT
  132.     ADD    DL,BL        ; ADD IN THE COLUMN INCREMENT
  133.     CMP    DL,0        ; AT LEFT EDGE OF SCREEN?
  134.     JGE    NOT_LEFT_EDGE
  135.  
  136.     MOV    DL,CRT_COLS    ; JUMP TO THE RIGHT EDGE
  137.     DEC    DL
  138.  
  139. NOT_LEFT_EDGE:
  140.     CMP    DL,CRT_COLS    ; AT RIGHT EDGE OF SCREEN YET?
  141.     JB    NOT_RIGHT_EDGE    ; IF NOT, KEEP MOVING RIGHT
  142.  
  143.     XOR    DL,DL        ; IF YES, WRAP TO LEFT EDGE
  144.  
  145. NOT_RIGHT_EDGE:
  146.     CMP    DH,0        ; AT TOP OF SCREEN YET?
  147.     JGE    NOT_AT_TOP
  148.  
  149.     MOV    DH,ROWS        ; JUMP DOWN TO THE BOTTOM
  150.  
  151. NOT_AT_TOP:
  152.     CMP    DH,ROWS        ; AT BOTTOM OF SCREEN?
  153.     JLE    NOT_AT_BOTTOM
  154.  
  155.     XOR    DH,DH        ; JUMP BACK TO THE TOP
  156.  
  157. NOT_AT_BOTTOM:
  158.     MOV    TOP_LEFT,DX    ; SAVE NEW CORNER LOCATION
  159.     CALL    REV_VIDEO    ; CHANGE IT TO REVERSE VIDEO
  160.     XOR    AH,AH        ; BIOS KEYBOARD INPUT
  161.     INT    16H        ; GET A KEYSTROKE
  162.     PUSH    AX
  163.     CALL    REV_VIDEO    ; PUT ATTRIBUTE BACK TO NORMAL
  164.     POP    AX
  165.     CMP    AH,1        ; IS IT ESCAPE?
  166.     JNE    NOT_ESC
  167.  
  168.     RET            ; JUST RETURN TO EXIT
  169.  
  170. NOT_ESC:
  171.     MOV    BX,0FF00H    ; INCREMENT TO SUBTRACT ONE ROW
  172.     CMP    AH,48H        ; IS IT UP ARROW?
  173.     JE    GET_KB_KEY1
  174.  
  175.     MOV    BX,0100H    ; INCREMENT TO ADD ONE ROW
  176.     CMP    AH,50H        ; IS IT DOWN ARROW?
  177.     JE    GET_KB_KEY1
  178.  
  179.     MOV    BX,0001H    ; INCREMENT TO ADD ONE COLUMN
  180.     CMP    AH,4DH        ; IS IT RIGHT ARROW?
  181.     JE    GET_KB_KEY1
  182.  
  183.     MOV    BX,00FFH    ; INCREMENT TO SUBTRACT ONE COLUMN
  184.     CMP    AH,4BH        ; IS IT LEFT ARROW?
  185.     JE    GET_KB_KEY1
  186.  
  187.     XOR    BX,BX
  188.     CMP    AL,13        ; IS IT A CARRIAGE RETURN?
  189.     JNE    NOT_CR
  190.  
  191.     MOV    DX,TOP_LEFT    ; A CARRIAGE RETURN WAS PRESSED
  192.     MOV    BOT_RIGHT,DX    ; INITIALIZE THE SECOND CORNER
  193.     CALL    REV_VIDEO    ; CHANGE IT BACK TO REVERSE VIDEO
  194.     JMP    SHORT GET_KB_KEY2
  195.  
  196. NOT_CR:
  197.     CMP    AH,22H        ; IS IT THE "G" KEY
  198.     JE    TYPE_BUFF    ; IF YES, THAN GET THE WINDOW
  199.  
  200.     JMP    GET_KB_KEY1    ; JUST GET ANOTHER KEY
  201.  
  202. TYPE_BUFF:
  203.     MOV    SEND_KEYS,1    ; SIGNAL TO SEND THE KEYS
  204.     RET
  205.  
  206. GET_KB_KEY2:
  207.     XOR    AH,AH
  208.     INT    16H        ; GET A KEYSTROKE
  209.  
  210. GOT_KEY2:
  211.     MOV    DX,BOT_RIGHT
  212.     CMP    AH,48H        ; IS IT UP ARROW?
  213.     JE    SUB_ROW        ; SUBTRACT A ROW FROM WINDOW
  214.  
  215.     CMP    AH,50H        ; IS IT DOWN ARROW?
  216.     JE    ADD_ROW        ; ADD A ROW TO THE WINDOW
  217.  
  218.     CMP    AH,4DH        ; IS IT RIGHT ARROW?
  219.     JE    ADD_COL        ; ADD A COLUMN TO THE WINDOW
  220.  
  221.     CMP    AH,4BH        ; IS IT LEFT ARROW?
  222.     JE    SUB_COL        ; SUBTRACT A COLUMN FROM WINDOW
  223.  
  224.     JMP    NOT_ARROW_KEY
  225.  
  226. SUB_COL:
  227.     DEC    DL        ; SUBTRACT A COLUMN
  228.     CMP    DL,LEFT_SIDE    ; DONT ERASE IT COMPLETELY
  229.     JL    GET_KB_KEY2
  230.  
  231.     MOV    RIGHT_SIDE,DL    ; SAVE NEW RIGHT SIDE COLUMN
  232.     INC    DL
  233.     JMP    SHORT COL_LOOP
  234.  
  235. ADD_COL:
  236.     INC    DL        ; ADD A COLUMN
  237.     CMP    DL,CRT_COLS    ; AT RIGHT EDGE OF SCREEN?
  238.     JAE    GET_KB_KEY2    ; STOP WHEN SCREEN IS FILLED
  239.  
  240.     MOV    RIGHT_SIDE,DL    ; SAVE NEW RIGHT SIDE COLUMN
  241.  
  242. COL_LOOP:
  243.     CALL    REV_VIDEO    ; REVERSE THIS CHARACTER
  244.     DEC    DH        ; MOVE TO NEXT ROW
  245.     CMP    DH,TOP_ROW    ; AT TOP ROW YET?
  246.     JGE    COL_LOOP    ; LOOP UNTIL AT TOP ROW
  247.  
  248.     JMP    GET_KB_KEY2
  249.  
  250. SUB_ROW:
  251.     DEC    DH
  252.     CMP    DH,TOP_ROW    ; AT TOP OF WINDOW?
  253.     JL    GET_KB_KEY2    ; DONT ERASE IT COMPLETELY
  254.  
  255.     MOV    BOT_ROW,DH
  256.     INC    DH
  257.     JMP    SHORT ROW_LOOP
  258.  
  259. ADD_ROW:
  260.     INC    DH
  261.     CMP    DH,ROWS        ; AT BOTTOM OF SCREEN?
  262.     JG    GET_KB_KEY2    ; STOP WHEN SCREEN IS FILLED
  263.  
  264.     MOV    BOT_ROW,DH
  265.  
  266. ROW_LOOP:
  267.     CALL    REV_VIDEO    ; REVERSE THIS CHARACTER
  268.     DEC    DL        ; MOVE TO NEXT COLUMN
  269.     CMP    DL,LEFT_SIDE    ; AT LEFT EDGE YET?
  270.     JGE    ROW_LOOP    ; CONTINUE UNTIL AT LEFT EDGE
  271.  
  272.     JMP    GET_KB_KEY2
  273.  
  274. NOT_ARROW_KEY:
  275.     CMP    AH,19H        ; WAS IT THE "P" KEY?
  276.     JNE    NOT_P
  277.  
  278.     MOV    SEND_CHAR,OFFSET PRINT_CHAR
  279.     JMP    READ_WINDOW
  280.  
  281. NOT_P:
  282.     MOV    BUFF_NEXT,BUFF_START
  283.     MOV    BUFF_LAST,BUFF_START
  284.     MOV    SEND_CHAR,OFFSET BUFF_CHAR
  285.     CMP    AH,1FH        ; WAS IT THE "S" KEY?
  286.     JNE    NOT_S
  287.  
  288.     MOV    SEND_CHAR,OFFSET BUFF_CHAR
  289.     JMP    READ_WINDOW
  290.  
  291. NOT_S:
  292.     CMP    AH,22H        ; IS IT THE "G" KEY
  293.     JNE    NOT_G
  294.  
  295.     MOV    SEND_KEYS,1
  296.     JMP    READ_WINDOW
  297.  
  298. NOT_G:
  299.     CMP    AH,21H        ; IS IT THE "F" KEY
  300.     JNE    NOT_F
  301.  
  302.     MOV    WRIT_FILE,0
  303.     CALL    GET_FILENAME
  304.     CMP    WRIT_FILE,-1    ; WAS ESCAPE REQUESTED?
  305.     JE    ERASE_BOX
  306.  
  307.     CALL    READ_WINDOW
  308.     MOV    WRIT_FILE,1
  309.     TEST    BUSY_FLAGS,00000011B     ; IS INT21 OR INT13 BUSY?
  310.     JNZ    RETURN        ; IF YES, WAIT TILL LATER
  311.  
  312.     CALL    WRITE_TO_FILE    ; IF NOT, DO IT NOW
  313.  
  314. RETURN:
  315.     RET
  316.  
  317. NOT_F:
  318.     CMP    AH,1        ; IS IT ESCAPE?
  319.     JE    ERASE_BOX    ; IF YES, ERASE BOX AND EXIT
  320.  
  321.     CMP    AL,13        ; IS IT A CARRIAGE RETURN?
  322.     JE    DISPLAY_HELP    ; IF YES, DISPLAY HELP
  323.  
  324.     JMP    GET_KB_KEY2    ; OTHERWISE JUST GET ANOTHER KEY
  325.  
  326. ERASE_BOX:
  327.     MOV    SEND_CHAR,OFFSET RETURN
  328.     JMP    READ_WINDOW
  329.  
  330. DISPLAY_HELP:
  331.     CALL    EXCHANGE_HELP    ; PUT UP THE HELP MENU
  332.     XOR    AH,AH
  333.     INT    16H        ; GET ANOTHER KEYSTROKE
  334.     PUSH    AX        ; SAVE THE KEYSTROKE
  335.     CALL    EXCHANGE_HELP    ; PULL DOWN THE HELP MENU
  336.     POP    AX        ; GET BACK THE KEYSTROKE
  337.     JMP    GOT_KEY2
  338.  
  339. ; *********************************************************************
  340. REV_VIDEO:
  341.     CALL    READ_CHAR    ; READ CHARACTER AND ATTRIBUTE
  342.     MOV    BL,AH        ; SAVE ATTRIBUTE IN BL
  343.     AND    BL,10001000B    ; GET BLINK AND INTENSITY BITS
  344.     AND    AH,01110111B    ; NOW LOOK ONLY AT COLOR BITS
  345.     MOV    CL,4        ; ROTATE FOUR COUNTS
  346.     ROR    AH,CL        ; ROTATE FOREGROUND AND BACKGROUND
  347.     OR    BL,AH        ; PUT BACK BLINK AND INTENSITY BITS
  348.     CALL    DISPLAY_CHAR    ; WRITE CHARACTER AND ATTRIBUTE
  349.     RET
  350.  
  351. ; *********************************************************************
  352. READ_WINDOW:
  353.     MOV    DX,TOP_LEFT    ; GET LOCATION OF FIRST CORNER
  354.  
  355. READ_LOOP:
  356.     CALL    REV_VIDEO    ; PUT ATTRIBUTE BACK TO NORMAL
  357.     CALL    READ_CHAR    ; READ THE CHARACTER
  358.     CALL    SEND_CHAR    ; CALL TO THE POINTER
  359.     INC    DL        ; NEXT CHAR IN ROW
  360.     CMP    DL,RIGHT_SIDE    ; AT THE RIGHT BORDER YET?
  361.     JLE    READ_LOOP    ; DO ALL CHARACTERS IN THIS ROW
  362.  
  363.     CALL    CR_LF        ; SEND CR-LF AFTER EACH ROW
  364.     INC    DH        ; MOVE TO NEXT ROW
  365.     MOV    DL,LEFT_SIDE    ; BACK TO LEFT EDGE
  366.     CMP    DH,BOT_ROW    ; AT THE BOTTOM BORDER YET?
  367.     JLE    READ_LOOP    ; READ ENTIRE WINDOW
  368.  
  369.     RET
  370.  
  371. ; *********************************************************************
  372. CR_LF:
  373.     MOV    AL,13
  374.     CALL    SEND_CHAR    ; SEND A CARRIAGE RETURN
  375.     MOV    AL,10
  376.     CALL    SEND_CHAR    ; SEND A LINE FEED
  377.     RET
  378.  
  379. ; *********************************************************************
  380. DISPLAY_CHAR:
  381.     PUSH    BX        ; SAVE THE ATTRIBUTE
  382.     CALL    GET_CURS_ADDR    ; GET ADDRESS OF BIOS CURSOR
  383.     MOV    ES:[BX],DX    ; TELL BIOS WHERE THE CURSOR IS
  384.     POP    BX        ; GET BACK THE ATTRIBUTE
  385.     MOV    BH,ACTIVE_PAGE    ; GET ACTIVE PAGE
  386.     PUSH    CX        ; SAVE THE LOOP COUNT
  387.     MOV    CX,1        ; WRITE 1 CHARACTER
  388.     MOV    AH,9        ; WRITE CHARACTER AND ATTRIBUTE
  389.     INT    10H
  390.     POP    CX        ; RECOVER LOOP COUNT
  391.     RET            ; DONE WRITING THE CHARACTER
  392.  
  393. ; *********************************************************************
  394. READ_CHAR:
  395.     CALL    GET_CURS_ADDR    ; GET ADDRESS OF BIOS CURSOR
  396.     MOV    ES:[BX],DX    ; TELL BIOS WHERE THE CURSOR IS
  397.     MOV    BH,ACTIVE_PAGE    ; GET ACTIVE PAGE
  398.     MOV    AH,8        ; BIOS FUNCTION TO READ CHARACTER
  399.     INT    10H        ; READ THE CHARACTER/ATTRIBUTE
  400.     RET
  401.  
  402. ; *********************************************************************
  403. PRINT_CHAR:
  404.     PUSH    DX
  405.     XOR    AH,AH        ; USE FUNCTION 0
  406.     XOR    DX,DX        ; PRINTER NUMBER 0
  407.     INT    17H        ; BIOS PRINT CHARACTER FUNCTION
  408.     ROR    AH,1        ; LOOK AT BIT ZERO
  409.     JNC    PRINT_OK    ; DID A TIMEOUT OCCUR?
  410.  
  411.     MOV    SEND_CHAR,OFFSET RETURN
  412.  
  413. PRINT_OK:
  414.     POP    DX
  415.     RET            ; DONE PRINTING CHARACTER
  416.  
  417. ; *********************************************************************
  418. BUFF_CHAR:
  419.     MOV    BX,BUFF_LAST    ; GET LOCATION OF LAST CHARACTER
  420.     MOV    [BX],AL        ; PUT THE CHARACTER IN BUFFER
  421.     INC    BX        ; ADVANCE THE POINTER
  422.     MOV    BUFF_LAST,BX    ; CHECK FOR BUFFER FULL
  423.     CMP    BX,BUFF_END    ; IS THE BUFFER FULL YET?
  424.     JNE    BUFF_OK        ; IF NOT, KEEP GOING
  425.  
  426.     MOV    SEND_CHAR,OFFSET RETURN
  427.  
  428. BUFF_OK:
  429.     RET            ; NOW ITS IN THE BUFFER
  430.  
  431. ; *********************************************************************
  432. GET_CURS_ADDR:
  433.     MOV    BL,ACTIVE_PAGE    ; GET THE CURRENT PAGE NUMBER
  434.     XOR    BH,BH        ; CONVERT TO A WORD OFFSET
  435.     SHL    BX,1        ; TIMES TWO FOR A WORD
  436.     ADD    BX,OFFSET CURSOR_POSN ; ADD IN BASE ADDRESS
  437.     RET
  438.  
  439. ; *********************************************************************
  440. EXCHANGE_HELP:
  441.     XOR    DX,DX        ; START AT TOP LEFT CORNER
  442.     LEA    SI,HELP_MENU
  443.  
  444. EXCHANGE_LOOP:
  445.     CMP    DL,12        ; AT LAST COLUMN IN THIS ROW YET?
  446.     JL    SWAP_CHAR
  447.  
  448.     XOR    DL,DL        ; BACK TO FIRST COLUMN
  449.     INC    DH        ; DO THE NEXT ROW
  450.     CMP    DH,7        ; AT LAST ROW YET?
  451.     JL    SWAP_CHAR    ; QUIT WHEN LAST ROW IS DONE
  452.  
  453.     RET
  454.  
  455. SWAP_CHAR:
  456.     CALL    READ_CHAR    ; READ CHARACTER AT THIS POSITION
  457.     XCHG    AL,CS:[SI]    ; SWAP WITH THE HELP TEXT
  458.     MOV    BL,AH        ; ATTRIBUTE IS THE SAME
  459.     CALL    DISPLAY_CHAR    ; PUT NEW CHARACTER ON SCREEN
  460.     INC    DL        ; POINT TO NEXT POSITION
  461.     INC    SI
  462.     JMP    EXCHANGE_LOOP
  463.  
  464. ; *********************************************************************
  465. GET_FILENAME:
  466.     LEA    SI,FILE_PROMPT    ; POINT TO THE PROMPT FOR SOURCE
  467.     XOR    DI,DI        ; USE THE PSP FOR BUFFER
  468.     XOR    DX,DX        ; PUT PROMPT AT TOP LEFT CORNER
  469.     MOV    CX,40        ; USE MAX OF 40 CHARACTERS
  470.  
  471. DISPLAY_PROMPT:
  472.     PUSH    CX        ; SAVE LOOP COUNT
  473.     CALL    READ_CHAR    ; GET CHARACTER ON THIS LINE
  474.     MOV    CS:[DI],AX    ; STORE IT IN THE PSP
  475.     INC    DI        ; ADD TWO FOR NEXT CHARACTER
  476.     INC    DI
  477.     MOV    AL,CS:[SI]    ; GET NEXT PROMPT CHARACTER
  478.     INC    SI        ; NEXT CHARACTER IN PROMPT
  479.     MOV    BL,47H        ; ATTRIBUTE FOR PROMPT
  480.     CALL    DISPLAY_CHAR    ; PUT UP THE PROMPT CHARACTER
  481.     INC    DL        ; POINT TO NEXT COLUMN
  482.     POP    CX        ; GET BACK LOOP COUNT
  483.     LOOP    DISPLAY_PROMPT    ; ENTIRE PROMPT AND FILENAME
  484.  
  485. FIND_LAST_LETTER:
  486.     DEC    SI        ; BACKUP TO LAST LETTER
  487.     DEC    DL        ; BACKUP TO LAST COLUMN
  488.     CMP    BYTE PTR [SI],0    ; IS THIS A LETTER?
  489.     JE    FIND_LAST_LETTER; BACKUP UNTIL A LETTER IS FOUND
  490.  
  491.     INC    DL        ; PUT BLINKING BOX AT LAST LETTER
  492.  
  493. READ_KB:
  494.     MOV    AL,219        ; ASCII FOR BOX CHARACTER
  495.     MOV    BL,47H+80H    ; MAKE IT A BLINKING BOX CHARACTER
  496.     CALL    DISPLAY_CHAR    ; WRITE THE BLINKING BOX
  497.     XOR    AH,AH        ; FUNCTIO 0 TO GET NEXT KEY
  498.     INT    16H        ; BIOS KEYBOARD INPUT
  499.     CMP    AL,13        ; IS IT A CARRIAGE RETURN?
  500.     JE    ERASE_PROMPT
  501.  
  502.     CMP    AL,8        ; IS IT A BACKSPACE?
  503.     JE    BACK_SPACE
  504.  
  505.     CMP    AH,1        ; IS IT ESCAPE?
  506.     JE    ESC_RET
  507.  
  508.     CMP    AL,"."        ; IS IT A VALID LETTER?
  509.     JL    READ_KB
  510.  
  511.     CMP    AL,"z"        ; IS IT A VALID LETTER?
  512.     JG    READ_KB
  513.  
  514.     CMP    DL,39        ; ONLY ALLOW 40 CHARACTERS
  515.     JGE    READ_KB
  516.  
  517. TTY_KEY:
  518.     MOV    BL,47H        ; ATTRIBUTE FOR FILENAME
  519.     CALL    DISPLAY_CHAR    ; WRITE THE LETTER
  520.     INC    DL        ; MOVE TO NEXT COLUMN
  521.     JMP    READ_KB        ; GET ANOTHER KEYSTROKE
  522.  
  523. BACK_SPACE:
  524.     CMP    DL,16        ; AT BEGINNING OF LINE?
  525.     JLE    READ_KB        ; IF YES, CAN'T BACKUP FROM HERE
  526.  
  527.     MOV    AL,0        ; WRITE A NORMAL BLANK (ASCII 0)
  528.     MOV    BL,47H        ; ATTRIBUTE FOR FILENAME
  529.     CALL    DISPLAY_CHAR    ; WRITE THE LETTER
  530.     DEC    DL        ; BACKUP THE CURSOR
  531.     JMP    READ_KB        ; THEN GET THE NEXT KEY
  532.  
  533. ESC_RET:
  534.     MOV    WRIT_FILE,-1    ; INDICATE ESCAPE IS REQUESTED
  535.  
  536. ERASE_PROMPT:
  537.     XOR    AL,AL        ; GET RID OF THE CURSOR
  538.     CALL    DISPLAY_CHAR    ; WRITE THE LETTER
  539.     LEA    DI,FILE_PROMPT    ; COPY TO FILENAME
  540.     XOR    SI,SI        ; COPY FROM PSP
  541.     XOR    DX,DX        ; PROMPT IS AT ROW ZERO
  542.     MOV    CX,40        ; COPY ALL 40 CHARACTERS
  543.  
  544. ERASE_LOOP:
  545.     CALL    READ_CHAR    ; GET CHARACTER ON THIS LINE
  546.     MOV    CS:[DI],AL    ; PUT IN BACK IN MEMORY
  547.     INC    DI
  548.     MOV    AX,CS:[SI]    ; GET THE ORIGINAL CHARACTER BACK
  549.     MOV    BL,AH        ; PUT ATTRIBUTE INTO BL
  550.     INC    SI
  551.     INC    SI
  552.     CALL    DISPLAY_CHAR    ; WRITE ORIGINAL CHARACTER
  553.     INC    DL        ; MOVE TO NEXT COLUMN
  554.     LOOP    ERASE_LOOP    ; ERASE THE ENTIRE PROMPT
  555.     RET
  556.  
  557. SNIPPER        ENDP
  558.  
  559. ; ----------------------------------------------------------------------; 
  560. ; THIS COPIES THE BUFFER CONTENTS TO A FILE. IT SHOULD ONLY BE CALLED    ; 
  561. ; WHEN DOS IS IN A STABLE AND REENTRANT CONDITION.            ; 
  562. ; ----------------------------------------------------------------------; 
  563.  
  564. WRITE_TO_FILE    PROC    NEAR
  565.  
  566.     ASSUME    DS:NOTHING, ES:NOTHING
  567.  
  568.     MOV    WRIT_FILE,0    ; TURN OFF REQUEST FLAG
  569.     PUSH    AX        ; MUST PRESERVE ALL REGISTERS
  570.     PUSH    BX
  571.     PUSH    CX
  572.     PUSH    DX
  573.     PUSH    DS
  574.     PUSH    ES
  575.     PUSH    CS
  576.     POP    DS
  577.  
  578.     ASSUME    DS:CSEG        ; DS POINTS TO OUR CODE SEGMENT
  579.  
  580.     MOV    AX,3524H    ; GET DOS CRITICAL ERROR VECTOR
  581.     INT    21H        ; DOS FUNCTION TO GET VECTOR
  582.     PUSH    BX        ; SAVE OLD VECTOR ON STACK
  583.     PUSH    ES
  584.  
  585. ; REPLACE THE DOS SEVERE ERROR INTERRUPT WITH OUR OWN ROUTINE.
  586.  
  587.     MOV    DX,OFFSET NEWINT24
  588.     MOV    AX,2524H    ; SETUP TO CHANGE INT 24h VECTOR
  589.     INT    21H        ; CHANGE DOS SEVERE ERROR VECTOR
  590.     MOV    DX,OFFSET FILENAME ; POINT TO FILENAME
  591.  
  592. ; FIRST TRY TO OPEN THE FILE.  IF DOS RETURNS WITH THE CARRY FLAG SET,
  593. ; THE FILE DIDN'T EXIST AND WE MUST CREATE IT.  ONCE THE FILE IS OPENED,
  594. ; ADVANCE THE FILE POINTER TO THE END OF FILE TO APPEND.
  595.  
  596.     MOV    AX,3D02H    ; DOS FUNCTION TO OPEN FILE
  597.     INT    21H        ; DOS WILL RETURN WITH CARRY FLAG
  598.     JC    FILE_NOT_FOUND    ; SET IF FILE DOESN'T EXIST.
  599.  
  600.     MOV    BX,AX        ; KEEP HANDLE IN BX ALSO
  601.     XOR    CX,CX        ; MOVE DOS FILE POINTER TO THE
  602.     XOR    DX,DX        ; END OF THE FILE. THIS LETS US
  603.     MOV    AX,4202H    ; APPEND THIS TO AN EXISTING FILE
  604.     INT    21H        ; DOS FUNCTION TO MOVE POINTER
  605.     JNC    WRITE_FILE    ; IF NO ERROR, CONTINUE TO WRITE
  606.  
  607. DOS_ERROR:
  608.     CMP    ERR_STAT,0    ; DID A SEVERE ERROR OCCUR?
  609.     JNE    REP_VECTOR    ; IF SEVERE ERROR, JUST QUIT
  610.  
  611.     JMP    SHORT CLOSE_FILE; JUST CLOSE THE FILE
  612.  
  613. FILE_NOT_FOUND:
  614.     CMP    ERR_STAT,0    ; DID A SEVERE ERROR OCCUR?
  615.     JNE    REP_VECTOR    ; IF SEVERE ERROR, JUST QUIT
  616.  
  617.     MOV    CX,0020H    ; ATTRIBUTE FOR NEW FILE
  618.     MOV    AH,3CH        ; CREATE FILE FOR WRITING
  619.     INT    21H        ; DOS FUNCTION TO CREATE FILE
  620.     JC    DOS_ERROR    ; ON ANY ERROR, TAKE JUMP
  621.  
  622.     MOV    BX,AX        ; SAVE HANDLE IN BX
  623.  
  624. WRITE_FILE:
  625.     MOV    DX,BUFF_START    ; POINT TO BUFFER
  626.     MOV    CX,BUFF_LAST    ; GET BUFFER POINTER
  627.     SUB    CX,DX        ; NUMBER OF CHARS IN BUFFER
  628.     MOV    AH,40H        ; DOS WRITE TO A DEVICE FUNCTION
  629.     INT    21H        ; WRITE TO THE FILE
  630.  
  631. CLOSE_FILE:
  632.     MOV    AH,3EH        ; DOS FUNCTION TO CLOSE THE FILE
  633.     INT    21H
  634.  
  635. REP_VECTOR:
  636.     POP    DS        ; GET INT 24H VECTOR FROM STACK
  637.     POP    DX
  638.     MOV    AX,2524H    ; RESTORE CRITICAL ERROR VECTOR
  639.     INT    21H        ; DOS FUNCTION TO CHANGE VECTOR
  640.     POP    ES        ; FINALLY RESTORE ALL REGISTERS
  641.     POP    DS
  642.     POP    DX
  643.     POP    CX
  644.     POP    BX
  645.     POP    AX
  646.     RET            ; FINISHED WRITING TO DISK
  647.  
  648. WRITE_TO_FILE    ENDP
  649.  
  650. ; ----------------------------------------------------------------------; 
  651. ; INTERRUPT 09 ROUTINE.  WATCH FOR TRIGGER KEY TO POP UP.        ;
  652. ; ----------------------------------------------------------------------; 
  653.  
  654. NEWINT09    PROC    FAR
  655.  
  656.     ASSUME    DS:NOTHING, ES:NOTHING
  657.  
  658.     STI            ; ALLOW OTHER INTERRUPTS
  659.     PUSH    AX        ; MUST SAVE PROCESSOR STATE
  660.     IN    AL,60H        ; GET THE SCAN CODE
  661.     CMP    AL,HOTKEY    ; IS IT THE HOT KEY?
  662.     JE    TRIGGER        ; IF YES, CHECK THE MASK
  663.  
  664. INT09_EXIT:
  665.     POP    AX        ; RESTORE THE PROCESSOR STATE
  666.     JMP    OLDINT09    ; CONTINUE WITH ROM ROUTINE
  667.  
  668. TRIGGER:
  669.     MOV    AH,2        ; GET KEYBOARD STATUS
  670.     INT    16H        ; BIOS KEYBOARD SERVICE
  671.     AND    AL,0FH        ; Take lower four bits
  672.     CMP    AL,SHIFT_MASK    ; IS ALT KEY DOWN?
  673.     JNZ    INT09_EXIT    ; IF NOT, IGNORE IT
  674.  
  675.     TEST    BUSY_FLAGS,00000100B ; IS SNIPPER ALREADY ACTIVE?
  676.     JNZ    INT09_EXIT    ; IF ACTIVE, THEN EXIT
  677.  
  678.     OR    BUSY_FLAGS,00000100B ; ITS ACTIVE NOW
  679.     PUSHF
  680.     CALL    OLDINT09    ; LET ROM PROCESS THE KEY
  681.     PUSH    BX        ; MUST PRESERVE ALL REGISTERS
  682.     PUSH    CX
  683.     PUSH    DX
  684.     PUSH    BP
  685.     PUSH    SI
  686.     PUSH    DI
  687.     PUSH    DS
  688.     PUSH    ES
  689.     PUSH    CS
  690.     POP    DS        ; SET DS TO CSEG
  691.     MOV    AX,BIOS_SEG    ; ES POINTS TO BIOS DATA AREA
  692.     MOV    ES,AX
  693.  
  694.     ASSUME    DS:CSEG, ES:BIOS_SEG
  695.  
  696.     CALL    GET_CURS_ADDR    ; CURSOR ADDRESS FOR THIS PAGE
  697.     PUSH    ES:[BX]        ; SAVE THE CURSOR LOCATION
  698.     CALL    SNIPPER        ; DO THE WINDOW
  699.     CALL    GET_CURS_ADDR    ; CURS0R ADDRESS FOR THIS PAGE
  700.     POP    ES:[BX]        ; GET BACK CURSOR POSITION
  701.     AND    BUSY_FLAGS,11111011B ; SNIPPER IS NOT ACTIVE
  702.     POP    ES        ; RESTORE ALL REGISTERS
  703.     POP    DS
  704.     POP    DI
  705.     POP    SI
  706.     POP    BP
  707.     POP    DX
  708.     POP    CX
  709.     POP    BX
  710.     POP    AX
  711.     IRET            ; NOW WERE ALL DONE
  712.  
  713. NEWINT09    ENDP
  714.  
  715. ; ----------------------------------------------------------------------; 
  716. ; INTERRUPT 13 ROUTINE. SET BIOS BUST BIT                ; 
  717. ; ----------------------------------------------------------------------; 
  718.  
  719. NEWINT13    PROC    FAR
  720.  
  721.     ASSUME    DS:NOTHING, ES:NOTHING
  722.  
  723.     OR    BUSY_FLAGS,00000010B    ; SET BIOS BUSY BIT
  724.     PUSHF
  725.     CALL    OLDINT13    ; DO THE BIOS FUNCTION
  726.     PUSHF            ; SAVE RESULT FLAGS
  727.     AND    BUSY_FLAGS,11111101B    ; CLEAR BIOS BUSY BIT
  728.     POPF            ; GET BACK RESULT FLAGS
  729.     STI            ; MUST RETURN WITH INTERUPTS ON
  730.     RET    2        ; RETURN BIOS RESULT FLAGS
  731.  
  732. NEWINT13    ENDP
  733.  
  734. ; ----------------------------------------------------------------------; 
  735. ; INTERRUPT 16 ROUTINE. INSERT KEYSTROKES FROM BUFFER            ;
  736. ; ----------------------------------------------------------------------; 
  737.  
  738. NEWINT16    PROC    FAR
  739.  
  740.     ASSUME    DS:NOTHING, ES:NOTHING
  741.  
  742.     PUSH    BX
  743.     CMP    SEND_KEYS,1    ; SENDING KEYS FROM BUFFER?
  744.     JE    INSERT_KEY    ; IF YES, THEN GET NEXT ONE
  745.  
  746.     CMP    WRIT_FILE,1    ; ANYTHING TO WRITE TO DISK?
  747.     JE    CHECK_DOS_STAT    ; IF YES, THIS IS THE TIME
  748.  
  749. BIOS_KB:
  750.     POP    BX
  751.     JMP    OLDINT16    ; JUST DO NORMAL KB ROUTINE
  752.  
  753. CHECK_DOS_STAT:
  754.     CMP    DOS_STAT,0AH    ; DOING READ STRING?
  755.     JE    BEGIN_NOW    ; IF YES, ITS SAFE TO BEGIN
  756.  
  757.     CMP    DOS_STAT,8    ; DOING KEYBOARD INPUT?
  758.     JNE    BIOS_KB        ; IF YES, ITS SAFE TO BEGIN
  759.  
  760. BEGIN_NOW:
  761.     STI            ; GET INTERRUPTS BACK ON
  762.     CALL    WRITE_TO_FILE    ; EMPTY THE BUFFER
  763.     JMP    BIOS_KB        ; CONTINUE WITH BIOS ROUTINE
  764.  
  765. INSERT_KEY:
  766.     STI            ; INTERRUPTS BACK ON
  767.     MOV    BX,BUFF_NEXT    ; GET ADDRESS OF NEXT BYTE
  768.     CMP    BX,BUFF_LAST    ; AT END OF BUFFER YET?
  769.     JL    GET_A_KEY    ; IF NOT, GET THE NEXT ONE
  770.  
  771.     MOV    SEND_KEYS,0    ; WHEN DONE, TURN OFF SEND SWITCH
  772.  
  773. GET_A_KEY:
  774.     MOV    AL,CS:[BX]    ; GET THE NEXT KEY CODE
  775.     CMP    AL,10        ; IS IT A LINE FEED?
  776.     JNE    NOT_LF        ; DONT RETURN THE LINE FEEDS
  777.  
  778.     INC    BUFF_NEXT    ; SKIP TO NEXT KEY
  779.     JMP    INSERT_KEY
  780.  
  781. NOT_LF:
  782.     CMP    AH,1        ; REQUEST FOR STATUS ONLY?
  783.     JE    RETURN_STATUS    ; IF YES, RETURN STATUS ONLY
  784.  
  785.     CMP    AH,0        ; REQUEST TO GET THE NEXT KEY
  786.     JNE    BIOS_KB        ; IF NOT, IGNORE THIS FUNCTION
  787.  
  788.     INC    BX        ; REMOVE THIS KEY FROM OUR BUFFER
  789.     MOV    BUFF_NEXT,BX    ; SAVE THE POINTER TO NEXT KEY
  790.  
  791. RETURN_STATUS:
  792.     OR    BL,1        ; CLEAR ZERO FLAG TO INDICATE A
  793.     POP    BX        ; KEY IS AVAILIABLE
  794.     RET    2        ; RETURN WITH THESE FLAGS
  795.  
  796. NEWINT16    ENDP
  797.  
  798. ; ----------------------------------------------------------------------; 
  799. ; INTERRUPT 21 ROUTINE.  THIS ROUTINE IS USED TO MONITOR DOS FUNCTION    ; 
  800. ; CALLS. IF THE BUFFER NEEDS TO BE FLUSHED, IT WIL BE DONE HERE.    ; 
  801. ; ----------------------------------------------------------------------; 
  802.  
  803. NEWINT21    PROC    FAR
  804.  
  805.     ASSUME    DS:NOTHING, ES:NOTHING
  806.  
  807.     STI
  808.     OR    AH,AH        ; DOING FUNCTION ZERO?
  809.     JNE    NOT_ZERO
  810.  
  811.     MOV    AH,4CH        ; IF YES, CHANGE IT TO A 4CH
  812.  
  813. NOT_ZERO:
  814.     OR    BUSY_FLAGS,00000001B    ; SET DOS BUSY BIT
  815.     MOV    DOS_STAT,AH
  816.     PUSHF            ; SIMULATE AN INTERRUPT
  817.     CALL    OLDINT21    ; DO THE DOS FUNCTION
  818.     PUSHF            ; SAVE THE RESULT FLAGS
  819.     AND    BUSY_FLAGS,11111110B    ; CLEAR DOS BUSY BIT
  820.     CMP    WRIT_FILE,1    ; ANYTHING TO WRITE TO DISK?
  821.     JNE    NO_WRITE    ; IF NOT JUST RETURN
  822.  
  823.     CALL    WRITE_TO_FILE    ; SAFE TO ACCESS DISK NOW
  824.  
  825. NO_WRITE:
  826.     POPF            ; RECOVER DOS RESULT FLAGS
  827.     RET    2        ; RETURN WITH DOS RESULT FLAGS
  828.  
  829. NEWINT21    ENDP
  830.  
  831. ; ----------------------------------------------------------------------; 
  832. ; NEW INTERRUPT 24H (CRITICAL DOS ERROR).  THIS INTERRUPT IS ONLY IN    ; 
  833. ; EFFECT ONLY DURING A WRITE SCREEN.  IT IS REQUIRED TO SUPPRESS THE    ; 
  834. ; 'ABORT, RETRY, IGNORE' MESSAGE.  ALL FATAL DISK ERRORS ARE IGNORED.    ; 
  835. ; ----------------------------------------------------------------------; 
  836.  
  837. NEWINT24    PROC    FAR
  838.  
  839.     ASSUME    CS:CSEG, DS:NOTHING, ES:NOTHING
  840.  
  841.     STI            ; TURN INTERRUPTS BACK ON
  842.     INC     ERR_STAT    ; SET THE ERROR FLAG
  843.          XOR    AL,AL        ; TELLS DOS TO IGNORE THE ERROR
  844.     IRET            ; THATS ALL WE DO HERE
  845.  
  846. NEWINT24    ENDP
  847.  
  848. ; ----------------------------------------------------------------------; 
  849. ; HERE IS THE CODE USED TO INITIALIZE SNIPPER.                ;
  850. ; ----------------------------------------------------------------------; 
  851.  
  852.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  853.  
  854. INITIALIZE:
  855.     LEA    DX,COPYRIGHT
  856.     MOV    AH,9        ; DOS DISPLAY STRING SERVICE
  857.     INT    21H        ; DISPLAY TITLE MESSAGE
  858.  
  859. ; SEARCH FOR AN PREVIOUSLY INSTALLED COPY OF SNIPPER
  860.  
  861.     NOT    BYTE PTR START    ; MODIFY TO AVOID FASLE MATCH
  862.     XOR    BX,BX        ; START SEARCH AT SEGMENT ZERO
  863.     MOV    AX,CS        ; COMPARE TO THIS CODE SEGMENT
  864.  
  865. NEXT_SEGMENT:
  866.     INC    BX        ; LOOK AT NEXT SEGMENT
  867.     CMP    AX,BX        ; UNTIL REACHING THIS CODE SEG
  868.     MOV    ES,BX
  869.     JE    NOT_INSTALLED
  870.  
  871.     LEA    SI,START    ; SETUP TO COMPARE STRINGS
  872.     MOV    DI,SI
  873.     MOV    CX,16        ; 16 BYTES MUST MATCH
  874.     REP    CMPSB        ; COMPARE DS:SI TO ES:DI
  875.     OR    CX,CX        ; DID THE STRINGS MATCH?
  876.     JNZ    NEXT_SEGMENT    ; IF NO MATCH, TRY NEXT SEGMENT
  877.  
  878.     LEA    DX,INSTALLED_MSG
  879.     JMP    SHORT ERR_EXIT
  880.  
  881. NOT_INSTALLED:
  882.     MOV    AH,30H
  883.     INT    21H        ; GET DOS VERSION NUMBER
  884.     CMP    AL,2        ; IS IT HIGHER THAN 2.0?
  885.     JAE    VER_OK        ; IF YES, PROCEED
  886.  
  887.     LEA    DX,BAD_DOS_MSG
  888.  
  889. ERR_EXIT:
  890.     MOV    AH,9        ; DOS DISPLAY STRING SERVICE
  891.     INT    21H        ; DISPLAY ERRER MESSAGE
  892.     RET            ; RETURN TO DOS
  893.  
  894. VER_OK:
  895.     INC    SI        ; POINT TO FIRST PARAMETER
  896.     MOV    SI,81H        ; POINT TO PARAMETER AREA
  897.     CALL    GET_PARAM    ; GET FIRST PARAMETER (ROWS)
  898.     PUSH    AX        ; SAVE THE ROW COUNT
  899.     CALL    GET_PARAM    ; GET SECOND PARAMETER (COLUMNS)
  900.     ADD    AX,2        ; ADD SPACE FOR CR AND LF
  901.     POP    BX        ; GET BACK FIRST PARAMETER
  902.     MUL    BX        ; PRODUCT OF ROWS AND COLUMNS
  903.     OR    AX,AX        ; WAS ANYTHING ENTERED?
  904.     JZ    NO_PARAMS    ; IF NOT, USE DEFAULT VALUE
  905.  
  906.     CMP    AX,10000    ; MAXIMUM BUFFER IS 10000 BYTES
  907.     JLE    SIZE_IS_OK
  908.  
  909.     MOV    AX,10000
  910.  
  911. SIZE_IS_OK:
  912.     ADD    AX,BUFF_START
  913.     MOV    BUFF_END,AX    ; SET THE NEW BUFFER SIZE
  914.  
  915. NO_PARAMS:
  916.     MOV    AX,BIOS_SEG    ; LOOK AT BIOS DATA AREA
  917.     MOV    ES,AX
  918.  
  919.     ASSUME    ES:BIOS_SEG
  920.  
  921.     CMP    ROWS,0        ; IS NUMBER OF ROWS ENTERED HERE
  922.     JNE    MUST_BE_EGA    ; IF YES, AN EGA MAY BE PRESENT
  923.  
  924.     MOV    ROWS,24        ; IF NOT EGA, MUST BE 24 ROWS
  925.  
  926. MUST_BE_EGA:
  927.  
  928.     ASSUME    ES:NOTHING
  929.  
  930.     MOV    AX,3509H    ; GET KEYBOARD BREAK VECTOR
  931.     INT    21H
  932.     MOV    WORD PTR [OLDINT09],BX    ; SAVE SEGMENT
  933.     MOV    WORD PTR [OLDINT09+2],ES; SAVE OFFSET
  934.     MOV    DX, OFFSET NEWINT09
  935.     MOV    AX, 2509H
  936.     INT    21H        ; DOS FUNCTION TO CHANGE VECTOR
  937.     MOV    AX,3513H    ; GET BIOS DISK INTERRUPT VECTOR
  938.     INT    21H
  939.     MOV    WORD PTR [OLDINT13],BX    ; SAVE SEGMENT
  940.     MOV    WORD PTR [OLDINT13+2],ES; SAVE OFFSET
  941.     MOV    DX, OFFSET NEWINT13
  942.     MOV    AX, 2513H
  943.     INT    21H        ; DOS FUNCTION TO CHANGE VECTOR
  944.     MOV    AX,3516H    ; GET KEYBOARD INPUT VECTOR
  945.     INT    21H
  946.     MOV    WORD PTR [OLDINT16],BX    ; SAVE SEGMENT
  947.     MOV    WORD PTR [OLDINT16+2],ES; SAVE OFFSET
  948.     MOV    DX, OFFSET NEWINT16
  949.     MOV    AX, 2516H
  950.     INT    21H        ; DOS FUNCTION TO CHANGE VECTOR
  951.     MOV    AX,3521H    ; GET DOS FUNCTION VECTOR
  952.     INT    21H
  953.     MOV    WORD PTR [OLDINT21],BX
  954.     MOV    WORD PTR [OLDINT21+2],ES
  955.     MOV    DX, OFFSET NEWINT21
  956.     MOV    AX, 2521H
  957.     INT    21H        ; DOS FUNCTION TO CHANGE VECTOR
  958.  
  959. ; ----------------------------------------------------------------------; 
  960. ; DEALLOCATE OUR COPY OF THE ENVIORNMENT.                ;
  961. ; EXIT USING INT 27H. LEAVE CODE AND SPACE FOR BUFFER RESIDENT.        ;
  962. ; ----------------------------------------------------------------------; 
  963.  
  964.     MOV    AX,DS:[002CH]    ; GET SEGMENT OF ENVIORNMENT
  965.     MOV    ES,AX        ; PUT IT INTO ES
  966.     MOV    AH,49H        ; RELEASE ALLOCATED MEMORY
  967.     INT    21H
  968.     MOV    DX,BUFF_END    ; LEAVE THIS MUCH RESIDENT
  969.     INT    27H        ; TEMINATE AND STAY RESIDENT
  970.  
  971. ; ------------------------------------------------------; 
  972. ; GET_PARAM RETRIEVES AN INTEGER FROM THE COMMAND LINE.    ; 
  973. ; ------------------------------------------------------; 
  974.  
  975. GET_PARAM:
  976.     XOR    AX,AX        ; CLEAR AX FOR TOTAL
  977.  
  978. GET_DIGIT:
  979.     MOV    BL,[SI]        ; GET CHARACTER INTO BL
  980.     CMP    BL,0DH        ; IS IT THE LAST ONE?
  981.     JE    DONE
  982.  
  983.     INC    SI        ; POINT TO NEXT CHARACTER
  984.     CMP    BL,","        ; IS IT THE DELIMITER?
  985.     JE    DONE
  986.  
  987.     SUB    BL,30H        ; CONVERT ASCII TO INTEGER
  988.     JC    GET_DIGIT    ; IS IT A VALID DIGIT
  989.  
  990.     CMP    BL,9
  991.     JA    GET_DIGIT    ; IF NOT VALID, JUST SKIP IT
  992.  
  993.     MOV    BH,10        ; TIMES 10 FOR NEXT DIGIT
  994.     MUL    BH        ; MULTIPLY SUM AND ADD THIS DIGIT
  995.     ADD    AL,BL        ; ADD DIGIT TO SUM
  996.     JMP    GET_DIGIT    ; READ ALL CHARACTERS ON LINE
  997.  
  998. DONE:
  999.     RET
  1000.  
  1001. CSEG    ENDS
  1002.  
  1003.     END    START
  1004.